package com.ormbench.ebean;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.ebean.Update;
import com.ormbench.base.dao.BaseDAO;

/**
 * Implements the generic CRUD data access operations.
 * <p>
 * To write a DAO, subclass and parameterize this class with your persistent class.
 * Of course, assuming that you have a traditional 1:1 approach for Entity:DAO design.
 * <p>
 */
public abstract class EbeanBaseDAO<T, ID extends Serializable> implements BaseDAO<T, ID> {

	// All models have these members
	public static final String ID = "id";
	public static final String CREATED_BY = "createdBy";
	public static final String CREATED_DATE = "createdDate";
	public static final String UPDATED_BY = "updatedBy";
	public static final String UPDATED_DATE = "updatedDate";

	private final Class<T> persistentClass;

	@SuppressWarnings("unchecked")
	protected EbeanBaseDAO() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	public Class<T> getPersistentClass() {
		return persistentClass;
	}

	public T create(T entity) {
		Ebean.save(entity);
		return entity;
	}
	
	public int createAll(List<T> entities) {
		return Ebean.save(entities.iterator());
	}

	public T read(ID id) {
		return Ebean.find(getPersistentClass(), id);
	}
	
	public T readByQuery(Query<T> query) {
		return query.findUnique();
	}

	public T update(T entity) {
		Ebean.save(entity);
		return entity;
	}
	
	public int updateAll(List<T> entities) {
		return Ebean.save(entities.iterator());
	}

	public void delete(T entity) {
		Ebean.delete(entity);
	}

    public void deleteById(ID id) {
    	T entity = read(id);
    	Ebean.delete(entity);
	}
    
    public void deleteByIds(List<ID> ids) {
    	Query<T> query = Ebean.createQuery(getPersistentClass());
    	query.where().in(ID, ids);
    	deleteByQuery(query);
	}
    
	public void deleteByQuery(Query<T> query) {
		List<T> entities = findByQuery(query);
		Ebean.delete(entities.iterator());
	}
	
	public void deleteAll() {
		String query = "delete from " + this.getPersistentClass().getSimpleName();
		Update<T> deleteAll = Ebean.createUpdate(persistentClass, query);
		deleteAll.execute();
	}

	public List<T> findByQuery(Query<T> query) {
		return query.findList();
	}
	
	public List<T> findByExample(T example) {
		Query<T> query = Ebean.createQuery(getPersistentClass());
		if (example != null) {
			query.where().iexampleLike(example);
		}
		return query.findList();
	}
	
	public List<T> findAll() {
		return Ebean.find(getPersistentClass()).findList(); 
	}
}

